package util;

import csvreader.CsvReader;
import org.apache.log4j.Logger;

import java.io.StringReader;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: pradeep
 * Date: Aug 16, 2010
 * Time: 8:27:00 AM
 * Utility class for "Statistics Attribute" Application (actual logic implemented here)
 */
public class StatisticsAttributesUtil {

    Logger gLogger = Logger.getLogger(StatisticsAttributesUtil.class);

    private static StatisticsAttributesUtil util = null;
    private List inputList = null;
    private List attributeList = null;
    private Long totalConditions = null;
    private Double pValueThreshold = null;

    /**
     * get instance of util class
     * @return
     */
    public static StatisticsAttributesUtil getInstance(){
        if(util == null){
            util = new StatisticsAttributesUtil();
        }
        return util;
    }


    /**
     * process method to calculate statistics attribute
     * @param data
     * @param totalConditions
     * @param pValueThreshold
     * @return
     */
    public List<String> processStatisticsAttributes(String data,Long totalConditions,Double pValueThreshold)
    {
        try
        {
            char delimiter = ChemSimilarityUtil.getInstance().getDelimiter(data);
            StringReader strReader = new StringReader(data);
            CsvReader reader = new CsvReader(strReader,delimiter);
            this.totalConditions = totalConditions;
            this.pValueThreshold = pValueThreshold;

            // Step1: Read user inputs
            readUserInput(reader);

            gLogger.info(inputList.size());

            // Step2: calculate arguments
            calculateArguments();

            // Step3: print
            //preapreNodeAttribute(attributeList,totalConditions);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return attributeList;
    }

    private void readUserInput(CsvReader reader){
        gLogger.info("comming into readUserInput method of StatisticsAttributesUtil");
        try
        {
            reader.readRecord();
            int colCount = reader.getColumnCount();
            gLogger.info("colCount :: "+colCount);
            inputList = new ArrayList();
            Map attributeMap = null;
            do{
                attributeMap = new HashMap();
                if( reader.get(0).trim().equalsIgnoreCase("PubChem ID") ){
                    //set labels
                    attributeMap.put("PUBCHEM-ID","PubChem ID");
                    for(int colId=1; colId<colCount ; colId++ ){

//                        if( (colId+1)%2 == 0){
//                            attributeMap.put("COND"+((colId+1)/2)+"-P-VALUE","condition-"+((colId+1)/2)+" p-value");
//                        }else if( (colId+1)%2 == 1){
//                            attributeMap.put("COND"+((colId+1)/2)+"-FOLD-CHANGE","condition-"+((colId+1)/2)+"  fold change");
//                        }
                        if( (colId+1)%2 == 0){
                            attributeMap.put("COND"+((colId+1)/2)+"-P-VALUE",reader.get(colId));
                        }else if( (colId+1)%2 == 1){
                            attributeMap.put("COND"+((colId+1)/2)+"-FOLD-CHANGE",reader.get(colId));
                        }
                    }
                }else{
                    attributeMap.put("PUBCHEM-ID",reader.get(0));
                    for(int colId=1; colId<colCount ; colId++ ){

                        if( (colId+1)%2 == 0){
                            attributeMap.put("COND"+((colId+1)/2)+"-P-VALUE", Double.parseDouble(reader.get(colId)) );
                        }else if( (colId+1)%2 == 1){
                            attributeMap.put("COND"+((colId+1)/2)+"-FOLD-CHANGE", Double.parseDouble(reader.get(colId)) );
                        }
                    }
                }
                inputList.add(attributeMap);
                //gLogger.info(attributeMap);
            }while(reader.readRecord());
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        gLogger.info("out from readUserInput method of StatisticsAttributesUtil");
    }

    /**
     * to prepare required parameters for processing than call actual process method
     */
    private void calculateArguments(){
        gLogger.info("comming into calculateArguments method of StatisticsAttributesUtil");
        if(inputList!=null && inputList.size()>0){
            attributeList = new ArrayList();

            //set label map
            Map labelMap = (HashMap)inputList.get(0);
            for(int index=1; index<=this.totalConditions; index++){
               //labelMap.put("COND"+index+"-DIRECTION","condition-"+index+" direction");
                labelMap.put("COND"+index+"-DIRECTION",labelMap.get("COND"+index+"-P-VALUE")+" direction");
            }
            attributeList.add(labelMap);

            //process input data
            Map dataMap = null;
            double foldChange = 0;
            double newFoldChange = 0;
            double pValue = 0;

            String conditionDirection = "";
            for(int index=1; index<this.inputList.size(); index++){
               dataMap = (HashMap) inputList.get(index);

               for(int indexConditions=1; indexConditions<=this.totalConditions; indexConditions++){
                 foldChange = (Double)dataMap.get("COND"+indexConditions+"-FOLD-CHANGE");


                 // calculateArg1  
                 if(foldChange<1.0){
                     conditionDirection = "DOWN";

                     // need to inverse foldChange
                     if(foldChange == (double) 0 ){
                        newFoldChange = 0;
                     }else{
                        if(foldChange > (double) 1 ){

                        }else{
                            newFoldChange = 1/foldChange;
                        }
                     }
                 }else
                 {
                     conditionDirection = "UP";

                     // leave is the same
                     newFoldChange = foldChange;
                 }

                 //calculateArg2
                 pValue = (Double)dataMap.get("COND"+indexConditions+"-P-VALUE");  
                 if( pValue >= pValueThreshold ){
                   //Update condition Direction as No Change
                   conditionDirection = "No Change";

                   //Update fold value by 1.0
                   newFoldChange = 1.0;  
                 }

                 dataMap.put("COND"+indexConditions+"-DIRECTION",conditionDirection);
                 dataMap.put("COND"+indexConditions+"-FOLD-CHANGE",newFoldChange);
               }
               //gLogger.info(dataMap);
               attributeList.add(dataMap);
            }
            
        }
        gLogger.info("out from calculateArguments method of StatisticsAttributesUtil");
    }

    /**
     * to preapre NodeAttribute
     * @param attributeList
     * @param totalConditions
     * @return
     */
    public String preapreNodeAttribute(List attributeList,Long totalConditions ){
        gLogger.info("comming into printResult method of StatisticsAttributesUtil");
        String returnString = "";
        if(attributeList!=null && attributeList.size()>0){
            DecimalFormat fmt = new DecimalFormat();
            fmt.setMinimumFractionDigits(3);
            fmt.setMaximumFractionDigits(3);
            
            String resultString="";
            Map map = null;
            for(int index=0; index<attributeList.size(); index++){
               map = (HashMap)attributeList.get(index);

               if(index==0){
                   // header labels
                   resultString = map.get("PUBCHEM-ID").toString();
                   for(int indexConditions=1; indexConditions<=totalConditions; indexConditions++){
                      resultString += "\t"+map.get("COND"+indexConditions+"-P-VALUE")+"";
                      resultString += "\t"+map.get("COND"+indexConditions+"-DIRECTION")+"";
                      resultString += "\t"+map.get("COND"+indexConditions+"-FOLD-CHANGE")+"";
                   }
               }else{
                   // Data
                   resultString = map.get("PUBCHEM-ID").toString();
                   for(int indexConditions=1; indexConditions<=totalConditions; indexConditions++){
                      resultString += "\t"+map.get("COND"+indexConditions+"-P-VALUE").toString();
                      resultString += "\t"+map.get("COND"+indexConditions+"-DIRECTION").toString();

                      double foldChange = (Double)map.get("COND"+indexConditions+"-FOLD-CHANGE");
                      resultString += "\t"+ fmt.format(foldChange);
                   }
               }
               if(returnString!=null && returnString.trim().length()==0){
                   returnString = resultString;
               }else{
                   returnString += "\n"+resultString;
               } 
            }
        }
        gLogger.info("out from printResult method of StatisticsAttributesUtil");
        return returnString;
    }

}
